﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Diagnostics;
using System.Management;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using WFDAL;

namespace WFBASE
{
    //security
    public class UserSec
    {
        #region mac address import
        [DllImport("Iphlpapi.dll")]
        static extern int SendARP(Int32 DestIP, Int32 SrcIP, ref Int64 MacAddr, ref Int32 PhyAddrLen);

        [DllImport("Ws2_32.dll")]
        static extern Int32 inet_addr(string ipaddr);
        #endregion

        #region 动态口令卡 et z 201
        //by Liang Zhengyi 
        //Date: 2011/6/2
        //otp Function 

        /* =============================================================================
         * Function   : ET_CheckPwdz201
         * Description: OTP Z201(TOTP) 认证接口
         * Parameter  : 
         *		authkey			令牌密钥（令牌提供商提供） //应存入数据库中，使用时select
         *      t               当前时间相对UTC Epoch秒数
         *      t0              起始参考时间相对UTC Epoch秒数(默认为0)
         *      x               TOTP变化周期(默认为60秒)
         *      drift           漂移值（用于时间校准）  //数据库中取，第一次给0.
         *      authwnd		    认证范围, 通常是0-20
         *      lastsucc        前一次认证成功的相对UTC Epoch秒数(为防止重放攻击) //数据库中取，第一次给0.
         *      otp				需要认证的动态口令
         *      otplen			需要认证的动态口令长度, 通常是6
         *      currsucc		认证成功后的相对UTC Epoch秒数  //认证成功后应写入数据库，供下次调用。
         *      currdft         认证成功后的当前漂移次数       //认证成功后应写入数据库，供下次调用。
         *
         * return     : 0 - 成功, 其他值为错误.
         *
         *int __stdcall ET_CheckPwdz201(char *authkey, uint64_t t, uint64_t t0, 
         *   unsigned int x, int drift, int authwnd, uint64_t lastsucc, 
         *   const char *otp, int otplen, uint64_t *currsucc, int *currdft);
         */

        /* =============================================================================
         * Function   : ET_Syncz201
         * Description: OTP Z201(TOTP) 同步接口
         * Parameter  : 
         *		authkey			令牌密钥，已经加密过的，需要对其进行解密
         *      t               当前时间相对UTC Epoch秒数
         *      t0              起始参考时间相对UTC Epoch秒数(默认为0)
         *      x               TOTP变化周期(默认为60秒)
         *      drift           漂移值
         *      syncwnd         同步范围, 通常是0-40
         *      lastsucc        前一次认证成功的相对UTC Epoch秒数(为防止重放攻击)
         *      otp1            需要同步的第一个动态口令
         *      otp1len			需要同步的第一个动态口令长度, 通常是6
         *      otp2            需要同步的第二个动态口令
         *      otp2len         需要同步的第二个动态口令长度, 通常是6   
         *      currsucc		认证成功后的相对UTC Epoch秒数   //同步成功后应写入数据库，供下次调用。
         *      currdft         认证成功后的当前漂移次数        //同步成功后应写入数据库，供下次调用。
         *
         * return     : 0 - 成功, 其他值为错误.
 
         *int __stdcall ET_Syncz201(char *authkey, uint64_t t, uint64_t t0, 
         *      unsigned int x, int drift, int syncwnd, uint64_t lastsucc, 
         *      const char *otp1, int otp1len, const char *otp2, int otp2len, 
         *      uint64_t *currsucc, int *currdft);
         */

        [DllImport("ET_OTPVerify.dll")]
        public static extern int ET_CheckPwdz201(string authkey, UInt64 t, UInt64 t0, uint x, int drift, int authwnd, UInt64 lastsucc, string otp, int otplen, ref UInt64 currsucc, ref int currdft);


        [DllImport("ET_OTPVerify.dll")]
        public static extern int ET_Syncz201(string authkey, UInt64 t, UInt64 t0, uint x, int drift, int syncwnd, UInt64 lastsucc, string otp1, int otp1len, string otp2, int otp2len, ref UInt64 currsucc, ref int currdft);

        UInt64 currsucc1 = 0;
        int currdft1 = 0;

        string otp_auth(string otpkey, string otp, UInt64 p_currsucc, int p_currdft, out UInt64 o_currsucc, out int o_currdft)
        {
            #region
            //currsucc1 = 0;
            //currdft1 = 0;
            //int iRet = 0;
            //string authkey = otpkey; //令牌密钥，应从服务器端的数据库中检索得到。此处为了方便测试，直接从客户端获取。

            //UInt64 currsucc = 0;
            //int currdft = 0;
            //p_currsucc = 0;
            //p_currdft = 0;

            //TimeSpan tsTimeSpan = DateTime.UtcNow - new DateTime(1970, 1, 1);
            //ulong ulgTimeStamp = (ulong)tsTimeSpan.TotalSeconds;

            //iRet = ET_CheckPwdz201(authkey, ulgTimeStamp, 0, 60, currdft1, 40, currsucc1, otp, 6, ref currsucc, ref currdft);
            //if (iRet == 0)
            //{
            //    //Message.Text += "<br>认证成功！";

            //    p_currsucc = currsucc;   //认证成功后应将“成功值”写回数据库，供接口调用。失败不要写回数据库。
            //    p_currdft = currdft;		//认证成功后应将“漂移值”写回数据库，供接口调用。失败不要写回数据库。
            //    //Message.Text += "<br> otp: " + otp;
            //    //Message.Text += "<br> currsucc: " + currsucc;
            //    //Message.Text += "<br> currdft: " + currdft;
            //    return "Y";
            //}
            //else
            //{
            //    return "认证失败！";
            //}
            //return "动态口令卡认证发生错误【"+iRet.ToString()+"】";//iRet;
            #endregion

            int iRet = 0;
            string authkey = otpkey; //令牌密钥，应从服务器端的数据库中检索得到。此处为了方便测试，直接从客户端获取。

            UInt64 currsucc = 0;
            int currdft = 0;

            TimeSpan tsTimeSpan = DateTime.UtcNow - new DateTime(1970, 1, 1);
            ulong ulgTimeStamp = (ulong)tsTimeSpan.TotalSeconds;

            //iRet = ET_CheckPwdz201(authkey, ulgTimeStamp, 0, 60, currdft1, 40, currsucc1, otp, 6, ref currsucc, ref currdft);
            iRet = ET_CheckPwdz201(authkey, ulgTimeStamp, 0, 60, p_currdft, 40, p_currsucc, otp, 6, ref currsucc, ref currdft);
            if (iRet == 0)
            {
                o_currsucc = currsucc;   //认证成功后应将“成功值”写回数据库，供接口调用。失败不要写回数据库。
                o_currdft = currdft;		//认证成功后应将“漂移值”写回数据库，供接口调用。失败不要写回数据库。
                return "Y";
            }
            else
            {
                o_currsucc = 0;
                o_currdft = 0;
                return "认证失败！";
            }
            //return "动态口令卡认证发生错误【" + iRet.ToString() + "】";//iRet;

        }

        string otp_sync(string otpkey, string otp1, string otp2, out UInt64 p_currsucc, out int p_currdft)
        {
            int iRet = 0;
            string authkey = otpkey;    //令牌密钥，应从服务器端的数据库中检索得到。

            UInt64 currsucc = 0;
            int currdft = 0;
            p_currsucc = 0;
            p_currdft = 0;

            TimeSpan tsTimeSpan = DateTime.UtcNow - new DateTime(1970, 1, 1);
            ulong ulgTimeStamp = (ulong)tsTimeSpan.TotalSeconds;

            iRet = ET_Syncz201(authkey, ulgTimeStamp, 0, 60, currdft1, 60, currsucc1, otp1, 6, otp2, 6, ref currsucc, ref currdft);
            if (iRet == 0)
            {
                // Message.Text += "<br>同步成功！";

                p_currsucc = currsucc;   //同步成功后应将“成功值”写回数据库，供接口调用。失败不要写回数据库。
                p_currdft = currdft;     //同步成功后应将“漂移值”写回数据库，供接口调用。失败不要写回数据库。
                //Message.Text += "<br> otp1: " + otp1;
                //Message.Text += "<br> otp2: " + otp2;
                //Message.Text += "<br> currsucc: " + currsucc;
                //Message.Text += "<br> currdft: " + currdft;
                return "Y";
            }
            else
            {
                return "同步失败！";
            }
            return "动态口令卡同步发生错误【" + iRet.ToString() + "】";//iRet;
        }
        #endregion

        OracleCommand cmd = new OracleCommand();
        /// <summary>
        /// 检查用户口令卡正确性
        /// </summary>
        /// <param name="p_LoginName"></param>
        /// <param name="p_OTP"></param>
        /// <returns></returns>
        public string ChkOTP(string p_LoginName, string p_OTP)
        {
            string sql = "SELECT up.*,ot.* FROM wf_userm u,wf_userpolicy up,wf_otplist ot " +
                "WHERE u.user_id=up.user_id AND up.policyval=ot.otpno AND " +
                "up.policy='504.003' AND lower(u.login_name)='" + p_LoginName.ToLower().Trim().Replace("'", "''") + "'";

            DataTable dt = cmd.Query(sql);
            if (dt == null || dt.Rows.Count == 0)
                return Message.GetMessage("NO_OTP_SET");// "参数错误，未找到口令卡验证设置!";

            UInt64 p_currsucc = 0;
            int p_currdft = 0;
            string res = "N";
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                p_currsucc = Convert.ToUInt64(dt.Rows[i]["currsucc"].ToString());
                p_currdft = Convert.ToInt32(dt.Rows[i]["currdft"].ToString());
                res = otp_auth(dt.Rows[i]["authkey"].ToString(), p_OTP, p_currsucc, p_currdft, out p_currsucc, out p_currdft);
                if (res == "Y")
                {
                    sql = "update wf_otplist set currsucc=" + p_currsucc + ",currdft=" + p_currdft + " where otpno='" + dt.Rows[i]["policyval"].ToString() + "'";
                    cmd.ExecuteSQL(sql);
                    return "Y";
                }
            }
            return res;
        }
        /// <summary>
        /// 檢查是否需要口令卡
        /// </summary>
        /// <param name="loginName"></param>
        /// <returns></returns>
        public String IsValidOtp(String loginName)
        {
            string sql = "SELECT count(*) FROM wf_userm u,wf_userpolicy up WHERE u.user_id=up.user_id AND up.policy='504.003' AND u.login_name='" + loginName.ToLower().Trim().Replace("'", "''") + "'";
            int res = Convert.ToInt32(new OracleCommand().QuerySclare(sql));
            if (res > 0)
                return "<otp>1</otp><ikey>0</ikey>";
            return "<otp>0</otp><ikey>0</ikey>";
        }

        /// <summary>
        /// Base64 加密
        /// </summary>
        /// <param name="StrString"></param>
        /// <returns></returns>
        public string ToBase64(string StrString)
        {
            byte[] data = System.Text.ASCIIEncoding.ASCII.GetBytes(StrString);
            string newString = Convert.ToBase64String(data);
            return newString;
        }

        public bool Login(string p_LoginName, string p_PWD, out string p_uid)
        {

            p_uid = "";

            string sql = "select * from wf_userm where UPPER(login_name)='" + formatStr(p_LoginName.ToUpper().Trim()) + "'";
            DataTable dt = cmd.Query(sql);
            if (dt == null || dt.Rows.Count == 0)
            {
                p_uid = Message.GetMessage("USER_NOT_EXIST");//"用户不存在或密码错误，请核对是否输入有误！";
                return false;
            }

            string md5pwd = ToBase64(p_PWD.Trim());
            if (p_PWD.Trim() != dt.Rows[0]["user_pwd"].ToString() && md5pwd != dt.Rows[0]["user_pwd"].ToString())
            {
                p_uid = Message.GetMessage("USER_NOT_EXIST");//"用户不存在或密码错误，请核对是否输入有误！";
                return false;
            }
            else
            {
                if (md5pwd != dt.Rows[0]["user_pwd"].ToString())
                {
                    sql = "update wf_userm set user_pwd='" + md5pwd + "' where user_id='" + dt.Rows[0]["user_id"].ToString() + "'";
                    cmd.ExecuteSQL(sql);
                }
                //user_id,user_name,user_IP,,user_group#user_group#user_group,fact_no,###
                string UserIP = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_HOST"].ToString();
                //string SecGroupId = System.Configuration.ConfigurationManager.AppSettings["signer"].ToString();
                bool IsAuth = true;// false;
                //sql = "select rule_id from wf_members where user_id='" + dt.Rows[0]["user_id"].ToString() + "'";
                //DataTable dtm = cmd.Query(sql);
                //string groups = "";
                //if (dtm != null)
                //{
                //    IsAuth = true;
                //    for (int i = 0; i < dtm.Rows.Count; i++)
                //    {
                //        groups += "#" + dtm.Rows[i]["rule_id"].ToString();
                //        if (dtm.Rows[i]["rule_id"].ToString() == SecGroupId)
                //            IsAuth = true;
                //    }
                //    if (groups != "")
                //        groups = groups.Substring(1);
                //}
                if (!IsAuth)//用户必须用户签核人员的权限才能进入系统
                {
                    p_uid = Message.GetMessage("NO_PRIVILAGE");//"对不起，您没有本系统的使用权限！请联络系统管理员了解。";
                    return false;
                }

                //策略登录
                switch (dt.Rows[0]["Assistant"].ToString())
                {
                    case "504.002"://MAC地址验证
                        string wf_usermac = this.GetRemoteMacByNetBIOS(UserIP);

                        DataTable dtup = cmd.Query("select * from wf_userpolicy where user_id='" + dt.Rows[0]["user_id"].ToString() + "' and policy='" + dt.Rows[0]["Assistant"].ToString() + "'");
                        if (dtup == null || dtup.Rows.Count == 0)
                        {
                            p_uid = Message.GetMessage("SEC_POLICY_ERROR");//"对不起，您的安全策略设置不正确，无法登陆系统！请联络系统管理员查核!";
                            return false;
                        }

                        if (dtup.Rows[0]["Policyval"].ToString() == wf_usermac || dtup.Rows[0]["Policyval2"].ToString() == wf_usermac || dtup.Rows[0]["Policyval3"].ToString() == wf_usermac)
                            break;
                        if (dtup.Rows[0]["Policyval"].ToString().ToLower() == "auto" ||
                            dtup.Rows[0]["Policyval2"].ToString().ToLower() == "auto" ||
                            dtup.Rows[0]["Policyval3"].ToString().ToLower() == "auto")
                        {
                            if (dtup.Rows[0]["Policyval"].ToString().ToLower() == "auto")
                                sql = "update wf_userpolicy set Policyval='" + wf_usermac + "' where user_id='" + dt.Rows[0]["user_id"].ToString() + "' and policy='" + dt.Rows[0]["Assistant"].ToString() + "'";
                            else if (dtup.Rows[0]["Policyval2"].ToString().ToLower() == "auto")
                                sql = "update wf_userpolicy set Policyval2='" + wf_usermac + "' where user_id='" + dt.Rows[0]["user_id"].ToString() + "' and policy='" + dt.Rows[0]["Assistant"].ToString() + "'";
                            else if (dtup.Rows[0]["Policyval3"].ToString().ToLower() == "auto")
                                sql = "update wf_userpolicy set Policyval3='" + wf_usermac + "' where user_id='" + dt.Rows[0]["user_id"].ToString() + "' and policy='" + dt.Rows[0]["Assistant"].ToString() + "'";

                            cmd.ExecuteSQL(sql);
                        }
                        else
                        {
                            //if (dt.Rows[0]["ikey"].ToString() != wf_usermac)
                            //{
                            p_uid = Message.GetMessage("SEC_POLICY_ERROR");//"对不起，您的安全策略不符，无法登陆系统！请联络系统管理员查核!";
                            return false;
                            //}
                        }
                        break;
                }

                p_uid = dt.Rows[0]["user_id"].ToString();
                // p_uid = dt.Rows[0]["user_id"].ToString() + "," + dt.Rows[0]["user_name"].ToString() + "," +
                //     UserIP + ",," + groups + "," + dt.Rows[0]["fact_no"].ToString() + ",###";
                System.Web.Security.FormsAuthentication.SetAuthCookie(dt.Rows[0]["user_id"].ToString(), false);
                return true;
            }


            return false;

        }

        private string GetMac()
        {
            string MAC = "";
            ManagementClass MC = new ManagementClass("Win32_NetworkAdapterConfiguration");
            ManagementObjectCollection MOC = MC.GetInstances();
            foreach (ManagementObject moc in MOC)
            {
                if (moc["IPEnabled"].ToString() == "True")
                {
                    MAC = moc["MacAddress"].ToString();
                }
            }
            return MAC;
        }

        public string GetMacAddress(string RemoteIP)
        {
            StringBuilder macAddress = new StringBuilder();
            try
            {
                Int32 remote = inet_addr(RemoteIP);

                Int64 macInfo = new Int64();
                Int32 length = 6;
                SendARP(remote, 0, ref macInfo, ref length);

                string temp = Convert.ToString(macInfo, 16).PadLeft(12, '0').ToUpper();

                int x = 12;
                for (int i = 0; i < 6; i++)
                {
                    if (i == 5)
                    {
                        macAddress.Append(temp.Substring(x - 2, 2));
                    }
                    else
                    {
                        macAddress.Append(temp.Substring(x - 2, 2) + "-");
                    }
                    x -= 2;
                }

                return macAddress.ToString();
            }
            catch
            {
                return macAddress.ToString();
            }
        }

        public string GetRemoteMacByNetBIOS(string clientIP)
        {
            if (clientIP == "127.0.0.1")
            {
                return GetMac();
            }
            else
            {
                return GetMacAddress(clientIP);
                //-----------------------------------
                string mac = "";
                System.Diagnostics.Process process = new System.Diagnostics.Process();
                process.StartInfo.FileName = "nbtstat";
                process.StartInfo.Arguments = "-a " + clientIP;
                process.StartInfo.UseShellExecute = false;
                process.StartInfo.CreateNoWindow = true;
                process.StartInfo.RedirectStandardOutput = true;
                process.Start();
                string output = process.StandardOutput.ReadToEnd();
                int length = output.IndexOf("MAC Address =");
                if (length > 0)
                {
                    mac = output.Substring(length + 14, 17);
                }
                return mac;
            }
        }

        public string UpdateUserInfor(string p_UserID, string p_LoginName, string p_UserName, string p_Pnlno,
            string p_Tel, string p_email, string p_Position)
        {
            string sql = "select * from wf_userm where user_id='" + p_UserID.Replace("'", "''") + "'";
            DataTable dt = cmd.Query(sql);
            if (dt == null || dt.Rows.Count == 0)
                return Message.GetMessage("USER_UPD_ERROR");//"用户资料异常，请查核后重试!";
            if (dt.Rows[0]["login_name"].ToString().ToUpper() != p_LoginName.ToUpper().Trim())
                return Message.GetMessage("ACCOUNT_ERROR");//"帐号不能修改，请查核后重试!";

            sql = "update wf_userm set user_name='" + formatStr(p_UserName) + "',pnl_no='" + formatStr(p_Pnlno) + "',user_tel='" +
                formatStr(p_Tel) + "',user_email='" + formatStr(p_email) + "',position='" + formatStr(p_Position) + "' where user_id='" + p_UserID + "'";
            if (cmd.ExecuteSQL(sql))
                return "Y";
            return Message.GetMessage("USER_UPD_ERROR");//"用户资料修改发生异常，请查核后重试!";
        }

        public string UpdateUserPwd(string p_LoginName, string p_OldPasswd, string p_NewPasswd)
        {
            string sql = "select * from wf_userm where UPPER(login_name)='" + formatStr(p_LoginName.ToUpper()) + "'";
            DataTable dt = cmd.Query(sql);
            if (dt == null || dt.Rows.Count == 0)
                return Message.GetMessage("USER_UPD_ERROR");//"用户资料异常，请查核后重试!";
            string md5pwd = ToBase64(p_OldPasswd.Trim());
            if (md5pwd != dt.Rows[0]["user_pwd"].ToString())
                return Message.GetMessage("PWD_CONFIRM_ERROR");//"旧密码不正确，请查核后重试!";
            if (p_NewPasswd.Trim() == "")
                return Message.GetMessage("PWD_NULL");//"密码不能为空，请查核后重试!";
            sql = "update wf_userm set user_pwd='" + formatStr(p_NewPasswd) + "' where upper(login_name)='" + formatStr(p_LoginName.ToUpper().Trim()) + "'";
            if (cmd.ExecuteSQL(sql))
                return "Y";
            return Message.GetMessage("USER_PWD_ERROR");//"修改密码发生异常，请查核资料后重试!";
        }
        public string ResetPWD(string p_UserId)
        {
            string defPWD = "123456";
            string sql = "SELECT * FROM Allguid WHERE c_guide_id='506.001'";
            DataTable dt = cmd.Query(sql);
            if (dt != null && dt.Rows.Count > 0)
                defPWD = dt.Rows[0]["c_guide_nm"].ToString();

            string md5pwd = ToBase64(defPWD);

            sql = "update wf_userm set user_pwd='" + formatStr(defPWD) + "' where user_id='" + p_UserId + "'";
            if (cmd.ExecuteSQL(sql))
                return "Y";
            return Message.GetMessage("USER_PWD_ERROR");//"修改密码发生异常，请查核资料后重试!";
        }
        string formatStr(string p_String)
        {
            if (p_String == null || p_String.Trim() == "")
                return "";
            string result = p_String.Replace("'", "''");
            return result;
        }
        // /xmlconfig/view_userm/telephone
        public string GetUserInfotByID(string p_UserID)
        {
            /*
             tel        : /xmlconfig/view_userm/telephone
             factno     : /xmlconfig/view_userm/fact_name
             loginName  : /xmlconfig/view_userm/loginname
             email      : /xmlconfig/view_userm/email
             userName   : /xmlconfig/view_userm/username
             deptno     : /xmlconfig/view_userm/dept_nm
             eUserName  : /xmlconfig/view_userm/userengname
             position   : /xmlconfig/view_userm/position
             ploginName : /xmlconfig/view_userm/emailaccount
             brandno    : /xmlconfig/view_userm/teamname
             */
            string sql = "select * from wf_userm where user_id='" + formatStr(p_UserID) + "'";
            DataTable dt = cmd.Query(sql);
            if (dt == null || dt.Rows.Count == 0)
                return Message.GetMessage("USER_UPD_ERROR");//"用户资料异常，请查核后重试!";
            string result = "<loginname>" + dt.Rows[0]["login_name"].ToString() + "</loginname><fact_name>" + dt.Rows[0]["fact_no"].ToString() +
                "</fact_name><telephone>_" + dt.Rows[0]["user_tel"].ToString() + "</telephone><email>" + dt.Rows[0]["user_email"].ToString() +
                "</email><username>" + dt.Rows[0]["user_name"].ToString() + "</username><dept_nm>" + dt.Rows[0]["pnl_branch_nm"].ToString() +
                "</dept_nm><userengname>" + dt.Rows[0]["user_ename"].ToString() + "</userengname><position>" + dt.Rows[0]["position"].ToString() +
                "</position><emailaccount>" + dt.Rows[0]["login_name"].ToString() + "</emailaccount><teamname>" + dt.Rows[0]["pnl_branch_nm"].ToString() +
                "</teamname><pnl_no><![CDATA[" + dt.Rows[0]["pnl_no"].ToString() + "]]></pnl_no>";
            result = "<NewDataSet><view_userm>" + result + "</view_userm></NewDataSet>";
            return result;
        }

    }
}
